home *** CD-ROM | disk | FTP | other *** search
- /*
- * PPPFSM.C -- PPP Finite State Machine
- *
- * This implementation of PPP is declared to be in the public domain.
- *
- * Jan 91 Bill_Simpson@um.cc.umich.edu
- * Computer Systems Consulting Services
- *
- * Acknowledgements and correction history may be found in PPP.C
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include "global.h"
- #include "mbuf.h"
- #include "iface.h"
- #include "ppp.h"
- #include "pppfsm.h"
- #include "ppplcp.h"
- #include "trace.h"
-
-
- char *fsmStates[] = {
- "Closed",
- "Listen",
- "Req Sent",
- "Ack Rcvd",
- "Ack Sent",
- "Opened",
- "TermSent"
- };
-
- char *fsmCodes[] = {
- NULLCHAR,
- "Config Req",
- "Config Ack",
- "Config Nak",
- "Config Reject",
- "Termin Req",
- "Termin Ack",
- "Code Reject",
- "Protocol Reject",
- "Echo Request",
- "Echo Reply",
- "Discard Request",
- };
-
- static int fsm_sendtermreq __ARGS((struct fsm_s *fsm_p));
- static int fsm_sendtermack __ARGS((struct fsm_s *fsm_p, byte_t id));
-
- static void fsm_timeout __ARGS((void *vp));
-
- static void fsm_reset __ARGS((struct fsm_s *fsm_p));
- static void fsm_opening __ARGS((struct fsm_s *fsm_p));
-
-
- /************************************************************************/
- /* Convert header in host form to network form */
- struct mbuf *
- htoncnf(cnf, bp)
- struct config_hdr *cnf;
- struct mbuf *bp;
- {
- register char *cp;
-
- /* Prepend bytes for LCP/IPCP header */
- bp = pushdown(bp, CONFIG_HDR_LEN);
-
- /* Load header with proper values */
- cp = bp->data;
- *cp++ = cnf->code;
- *cp++ = cnf->id;
- put16(cp, cnf->len);
-
- return bp;
- }
-
- /* Extract header from incoming packet */
- int
- ntohcnf(cnf, bpp)
- struct config_hdr *cnf;
- struct mbuf **bpp;
- {
- char cnfb[CONFIG_HDR_LEN];
-
- if ( cnf == NULL )
- return -1;
-
- if ( pullup( bpp, cnfb, CONFIG_HDR_LEN ) < CONFIG_HDR_LEN )
- return -1;
-
- cnf->code = cnfb[0];
- cnf->id = cnfb[1];
- cnf->len = get16(&cnfb[2]);
- return 0;
- }
-
- /***************************************/
- /* Extract configuration option header */
- int
- ntohopt(opt,bpp)
- struct option_hdr *opt;
- struct mbuf **bpp;
- {
- char optb[OPTION_HDR_LEN];
-
- if ( opt == NULL )
- return -1;
-
- if ( pullup( bpp, optb, OPTION_HDR_LEN ) < OPTION_HDR_LEN )
- return -1;
-
- opt->type = optb[0];
- opt->len = optb[1];
- return 0;
- }
-
-
- /************************************************************************/
- void
- fsm_no_action(fsm_p)
- struct fsm_s *fsm_p;
- {
- PPP_DEBUG_ROUTINES("fsm_no_action()");
- }
- int
- fsm_no_check(fsm_p, hdr, bp)
- struct fsm_s *fsm_p;
- struct config_hdr *hdr;
- struct mbuf *bp;
- {
- PPP_DEBUG_ROUTINES("fsm_no_check()");
- return 0;
- }
-
-
- /************************************************************************/
- /* General log routine */
- void
- fsm_log(fsm_p, comment)
- struct fsm_s *fsm_p;
- char *comment;
- {
- if (PPPtrace > 1)
- trace_log(PPPiface,"%s PPP/%s %-8s; %s",
- fsm_p->ppp_p->iface->name,
- fsm_p->pdc->name,
- fsmStates[fsm_p->state],
- comment);
- }
-
-
- /************************************************************************/
- /* Set a timer in case an expected event does not occur */
- void
- fsm_timer(fsm_p)
- struct fsm_s *fsm_p;
- {
- PPP_DEBUG_ROUTINES("fsm_timer()");
-
- start_timer( &(fsm_p->timer) );
- }
-
-
- /************************************************************************/
- /* Send a packet to the remote host */
- int
- fsm_send(fsm_p,code,id,data)
- struct fsm_s *fsm_p;
- byte_t code;
- byte_t id;
- struct mbuf *data;
- {
- struct ppp_s *ppp_p = fsm_p->ppp_p;
- struct iface *iface = ppp_p->iface;
- struct config_hdr hdr;
- struct mbuf *bp = NULL; /* OIS */
-
- switch( hdr.code = code ) {
- case CONFIG_REQ:
- case TERM_REQ:
- case ECHO_REQ:
- /* Save ID field for match against replies from remote host */
- fsm_p->lastid = ppp_p->id;
- /* fallthru */
- case PROT_REJ:
- case DISCARD_REQ:
- /* Use a unique ID field value */
- hdr.id = ppp_p->id++;
- break;
-
- case CONFIG_ACK:
- case CONFIG_NAK:
- case CONFIG_REJ:
- case TERM_ACK:
- case CODE_REJ:
- case ECHO_REPLY:
- /* Use ID sent by remote host */
- hdr.id = id;
- break;
-
- default:
- /* we're in trouble */
- trace_log(PPPiface, "%s PPP/%s %-8s;"
- " Send with bogus code: %d",
- iface->name,
- fsm_p->pdc->name,
- fsmStates[fsm_p->state],
- code);
- return -1;
- };
-
- switch( code ) {
- case ECHO_REQ:
- case ECHO_REPLY:
- case DISCARD_REQ:
- {
- struct lcp_s *lcp_p = fsm_p->pdv;
- bp = pushdown(bp, 4);
- put32(bp->data, lcp_p->local.work.magic_number);
- data = bp;
- }
- };
-
- hdr.len = len_p(data) + CONFIG_HDR_LEN;
-
- /* Prepend header to packet data */
- if ((data = htoncnf(&hdr,data)) == NULLBUF)
- return -1;
-
- if (PPPtrace > 1) {
- trace_log(PPPiface, "%s PPP/%s %-8s;"
- " Sending %s, id: %d, len: %d",
- iface->name,
- fsm_p->pdc->name,
- fsmStates[fsm_p->state],
- fsmCodes[code],
- hdr.id,hdr.len);
- }
-
- ppp_p->OutNCP[fsm_p->pdc->fsmi]++;
-
- return( (*iface->output)
- (iface, NULLCHAR, NULLCHAR, fsm_p->pdc->protocol, data) );
- }
-
-
- /************************************************************************/
- /* Send a configuration request */
- int
- fsm_sendreq(fsm_p)
- struct fsm_s *fsm_p;
- {
- struct mbuf *bp;
-
- PPP_DEBUG_ROUTINES("fsm_sendreq()");
-
- if ( fsm_p->retry <= 0 )
- return -1;
-
- fsm_p->retry--;
- fsm_timer(fsm_p);
-
- bp = (*fsm_p->pdc->makereq)(fsm_p);
- return( fsm_send(fsm_p, CONFIG_REQ, 0, bp) );
- }
-
-
- /************************************************************************/
- /* Send a termination request */
- static int
- fsm_sendtermreq(fsm_p)
- struct fsm_s *fsm_p;
- {
- PPP_DEBUG_ROUTINES("fsm_sendtermreq()");
-
- if ( fsm_p->retry <= 0 )
- return -1;
-
- fsm_p->retry--;
- fsm_timer(fsm_p);
- return( fsm_send(fsm_p, TERM_REQ, 0, NULLBUF) );
- }
-
-
- /************************************************************************/
- /* Send Terminate Ack */
- static int
- fsm_sendtermack(fsm_p,id)
- struct fsm_s *fsm_p;
- byte_t id;
- {
- PPP_DEBUG_ROUTINES("fsm_sendtermack()");
-
- return( fsm_send(fsm_p, TERM_ACK, id, NULLBUF) );
- }
-
-
- /************************************************************************/
- /* Reset state machine */
- static void
- fsm_reset(fsm_p)
- struct fsm_s *fsm_p;
- {
- PPP_DEBUG_ROUTINES("fsm_reset()");
-
- fsm_p->state = (fsm_p->flags & (FSM_ACTIVE | FSM_PASSIVE))
- ? fsmLISTEN : fsmCLOSED;
- fsm_p->retry = fsm_p->try_req;
- fsm_p->retry_nak = fsm_p->try_nak;
-
- (*fsm_p->pdc->reset)(fsm_p);
- }
-
-
- /************************************************************************/
- /* Configuration negotiation complete */
- static void
- fsm_opening(fsm_p)
- struct fsm_s *fsm_p;
- {
- fsm_log(fsm_p, "Opened");
-
- stop_timer(&(fsm_p->timer));
-
- (*fsm_p->pdc->opening)(fsm_p);
- fsm_p->state = fsmOPENED;
- }
-
-
- /************************************************************************/
- /* E V E N T P R O C E S S I N G */
- /************************************************************************/
-
- /* Process incoming packet */
- void
- fsm_proc(fsm_p,bp)
- struct fsm_s *fsm_p;
- struct mbuf *bp;
- {
- struct config_hdr hdr;
-
- PPPtrace = fsm_p->ppp_p->trace;
- PPPiface = fsm_p->ppp_p->iface;
-
- if ( ntohcnf(&hdr, &bp) == -1 )
- fsm_log( fsm_p, "short configuration packet" );
-
- if (PPPtrace > 1)
- trace_log(PPPiface, "%s PPP/%s %-8s;"
- " Processing %s, id: %d, len: %d",
- fsm_p->ppp_p->iface->name,
- fsm_p->pdc->name,
- fsmStates[fsm_p->state],
- fsmCodes[hdr.code],
- hdr.id, hdr.len);
-
- hdr.len -= CONFIG_HDR_LEN; /* Length includes envelope */
- trim_mbuf(&bp, hdr.len); /* Trim off padding */
-
- switch(hdr.code) {
- case CONFIG_REQ:
- switch(fsm_p->state) {
- case fsmOPENED: /* Unexpected event? */
- (*fsm_p->pdc->closing)(fsm_p);
- fsm_reset(fsm_p);
- /* fallthru */
- case fsmLISTEN:
- (*fsm_p->pdc->starting)(fsm_p);
- fsm_sendreq(fsm_p);
- /* fallthru */
- case fsmREQ_Sent:
- case fsmACK_Sent: /* Unexpected event? */
- fsm_p->state =
- ((*fsm_p->pdc->request)(fsm_p, &hdr, bp) == 0)
- ? fsmACK_Sent : fsmREQ_Sent;
- break;
-
- case fsmACK_Rcvd:
- if ((*fsm_p->pdc->request)(fsm_p, &hdr, bp) == 0) {
- fsm_opening(fsm_p);
- } else {
- /* give peer time to respond */
- fsm_timer(fsm_p);
- }
- break;
-
- case fsmCLOSED:
- /* Don't accept any connections */
- fsm_sendtermack(fsm_p, hdr.id);
- /* fallthru */
- case fsmTERM_Sent:
- /* We are attempting to close connection; */
- /* wait for timeout to resend a Terminate Request */
- free_p(bp);
- break;
- };
- break;
-
- case CONFIG_ACK:
- switch(fsm_p->state) {
- case fsmREQ_Sent:
- if ((*fsm_p->pdc->ack)(fsm_p, &hdr, bp) == 0) {
- fsm_p->state = fsmACK_Rcvd;
- }
- break;
-
- case fsmACK_Sent:
- if ((*fsm_p->pdc->ack)(fsm_p, &hdr, bp) == 0) {
- fsm_opening(fsm_p);
- }
- break;
-
- case fsmOPENED: /* Unexpected event? */
- (*fsm_p->pdc->closing)(fsm_p);
- (*fsm_p->pdc->starting)(fsm_p);
- fsm_reset(fsm_p);
- /* fallthru */
- case fsmACK_Rcvd: /* Unexpected event? */
- free_p(bp);
- fsm_sendreq(fsm_p);
- fsm_p->state = fsmREQ_Sent;
- break;
-
- case fsmCLOSED:
- case fsmLISTEN:
- /* Out of Sync; kill the remote */
- fsm_sendtermack(fsm_p, hdr.id);
- /* fallthru */
- case fsmTERM_Sent:
- /* We are attempting to close connection; */
- /* wait for timeout to resend a Terminate Request */
- free_p(bp);
- break;
- };
- break;
-
- case CONFIG_NAK:
- switch(fsm_p->state) {
- case fsmREQ_Sent:
- case fsmACK_Sent:
- /* Update our config request to reflect NAKed options */
- if ((*fsm_p->pdc->nak)(fsm_p, &hdr, bp) == 0) {
- /* Send updated config request */
- fsm_sendreq(fsm_p);
- }
- break;
-
- case fsmOPENED: /* Unexpected event? */
- (*fsm_p->pdc->closing)(fsm_p);
- (*fsm_p->pdc->starting)(fsm_p);
- fsm_reset(fsm_p);
- /* fallthru */
- case fsmACK_Rcvd: /* Unexpected event? */
- free_p(bp);
- fsm_sendreq(fsm_p);
- fsm_p->state = fsmREQ_Sent;
- break;
-
- case fsmCLOSED:
- case fsmLISTEN:
- /* Out of Sync; kill the remote */
- fsm_sendtermack(fsm_p, hdr.id);
- /* fallthru */
- case fsmTERM_Sent:
- /* We are attempting to close connection; */
- /* wait for timeout to resend a Terminate Request */
- free_p(bp);
- break;
- };
- break;
-
- case CONFIG_REJ:
- switch(fsm_p->state) {
- case fsmREQ_Sent:
- case fsmACK_Sent:
- if((*fsm_p->pdc->reject)(fsm_p, &hdr, bp) == 0) {
- fsm_sendreq(fsm_p);
- }
- break;
-
- case fsmOPENED: /* Unexpected event? */
- (*fsm_p->pdc->closing)(fsm_p);
- (*fsm_p->pdc->starting)(fsm_p);
- fsm_reset(fsm_p);
- /* fallthru */
- case fsmACK_Rcvd: /* Unexpected event? */
- free_p(bp);
- fsm_sendreq(fsm_p);
- fsm_p->state = fsmREQ_Sent;
- break;
-
- case fsmCLOSED:
- case fsmLISTEN:
- /* Out of Sync; kill the remote */
- fsm_sendtermack(fsm_p, hdr.id);
- /* fallthru */
- case fsmTERM_Sent:
- /* We are attempting to close connection; */
- /* wait for timeout to resend a Terminate Request */
- free_p(bp);
- break;
- };
- break;
-
- case TERM_REQ:
- fsm_log(fsm_p, "Peer requested Termination");
-
- switch(fsm_p->state) {
- case fsmOPENED:
- fsm_sendtermack(fsm_p, hdr.id);
- (*fsm_p->pdc->closing)(fsm_p);
- (*fsm_p->pdc->stopping)(fsm_p);
- fsm_reset(fsm_p);
- break;
-
- case fsmACK_Rcvd:
- case fsmACK_Sent:
- fsm_p->state = fsmREQ_Sent;
- /* fallthru */
- case fsmREQ_Sent:
- case fsmTERM_Sent:
- /* waiting for timeout */
- /* fallthru */
- case fsmCLOSED:
- case fsmLISTEN:
- /* Unexpected, but make them happy */
- fsm_sendtermack(fsm_p, hdr.id);
- break;
- };
- break;
-
- case TERM_ACK:
- switch(fsm_p->state) {
- case fsmTERM_Sent:
- stop_timer(&(fsm_p->timer));
-
- fsm_log(fsm_p, "Terminated");
- (*fsm_p->pdc->stopping)(fsm_p);
- fsm_reset(fsm_p);
- break;
-
- case fsmOPENED:
- /* Remote host has abruptly closed connection */
- fsm_log(fsm_p, "Terminated unexpectly");
- (*fsm_p->pdc->closing)(fsm_p);
- fsm_reset(fsm_p);
- if ( fsm_sendreq(fsm_p) == 0 ) {
- fsm_p->state = fsmREQ_Sent;
- }
- break;
-
- case fsmACK_Sent:
- case fsmACK_Rcvd:
- fsm_p->state = fsmREQ_Sent;
- /* fallthru */
- case fsmREQ_Sent:
- /* waiting for timeout */
- /* fallthru */
- case fsmCLOSED:
- case fsmLISTEN:
- /* Unexpected, but no action needed */
- break;
- };
- break;
-
- case CODE_REJ:
- trace_log(PPPiface,"%s PPP/%s Code Reject;"
- " indicates faulty implementation",
- fsm_p->ppp_p->iface->name,
- fsm_p->pdc->name);
- (*fsm_p->pdc->stopping)(fsm_p);
- fsm_reset(fsm_p);
- free_p(bp);
- break;
-
- case PROT_REJ:
- trace_log(PPPiface,"%s PPP/%s Protocol Reject;"
- " please do not use this protocol",
- fsm_p->ppp_p->iface->name,
- fsm_p->pdc->name);
- free_p(bp);
- break;
-
- case ECHO_REQ:
- switch(fsm_p->state) {
- case fsmOPENED:
- fsm_send( fsm_p, ECHO_REPLY, hdr.id, bp );
- break;
-
- case fsmCLOSED:
- case fsmLISTEN:
- /* Out of Sync; kill the remote */
- fsm_sendtermack(fsm_p, hdr.id);
- /* fallthru */
- case fsmREQ_Sent:
- case fsmACK_Rcvd:
- case fsmACK_Sent:
- case fsmTERM_Sent:
- /* ignore */
- free_p(bp);
- break;
- };
- break;
-
- case ECHO_REPLY:
- case DISCARD_REQ:
- case QUALITY_REPORT:
- free_p(bp);
- break;
-
- default:
- trace_log(PPPiface,"%s PPP/%s Unknown packet type: %d;"
- " Sending Code Reject",
- fsm_p->ppp_p->iface->name,
- fsm_p->pdc->name,
- hdr.code);
-
- hdr.len += CONFIG_HDR_LEN; /* restore length */
- bp = htoncnf( &hdr, bp ); /* put header back on */
- fsm_send( fsm_p, CODE_REJ, hdr.id, bp );
-
- switch(fsm_p->state) {
- case fsmREQ_Sent:
- case fsmACK_Rcvd:
- case fsmACK_Sent:
- case fsmOPENED:
- fsm_p->state = fsmLISTEN;
- break;
-
- case fsmCLOSED:
- case fsmLISTEN:
- case fsmTERM_Sent:
- /* no change */
- break;
- };
- break;
- }
- }
-
-
- /************************************************************************/
- /* Timeout while waiting for reply from remote host */
- static void
- fsm_timeout(vp)
- void *vp;
- {
- struct fsm_s *fsm_p = (struct fsm_s *)vp;
-
- PPPtrace = fsm_p->ppp_p->trace;
- PPPiface = fsm_p->ppp_p->iface;
-
- fsm_log( fsm_p, "Timeout" );
-
- switch(fsm_p->state) {
- case fsmREQ_Sent:
- case fsmACK_Rcvd:
- case fsmACK_Sent:
- if (fsm_p->retry > 0) {
- fsm_sendreq(fsm_p);
- fsm_p->state = fsmREQ_Sent;
- } else {
- fsm_log(fsm_p, "Request retry exceeded");
- fsm_reset(fsm_p);
- }
- break;
-
- case fsmTERM_Sent:
- if (fsm_p->retry > 0) {
- fsm_sendtermreq(fsm_p);
- } else {
- fsm_log(fsm_p, "Terminate retry exceeded");
- (*fsm_p->pdc->stopping)(fsm_p);
- fsm_reset(fsm_p);
- }
- break;
-
- case fsmCLOSED:
- case fsmLISTEN:
- case fsmOPENED:
- /* nothing to do */
- break;
- }
- }
-
-
- /************************************************************************/
- /* I N I T I A L I Z A T I O N */
- /************************************************************************/
-
- /* Start FSM (after open event, and physical line up) */
- void
- fsm_start(fsm_p)
- struct fsm_s *fsm_p;
- {
- if ( fsm_p->pdv == NULL )
- return;
-
- PPPtrace = fsm_p->ppp_p->trace;
- PPPiface = fsm_p->ppp_p->iface;
-
- fsm_log(fsm_p, "Start");
-
- if ( !(fsm_p->flags & (FSM_ACTIVE | FSM_PASSIVE)) )
- return;
-
- switch ( fsm_p->state ) {
- case fsmCLOSED:
- case fsmLISTEN:
- case fsmTERM_Sent:
- (*fsm_p->pdc->starting)(fsm_p);
- fsm_reset(fsm_p);
-
- if ( fsm_p->flags & FSM_ACTIVE ){
- fsm_sendreq(fsm_p);
- fsm_p->state = fsmREQ_Sent;
- }
- break;
- default:
- /* already started */
- break;
- };
- }
-
-
- /************************************************************************/
- /* Physical Line Down Event */
- void
- fsm_down(fsm_p)
- struct fsm_s *fsm_p;
- {
- if ( fsm_p->pdv == NULL )
- return;
-
- PPPtrace = fsm_p->ppp_p->trace;
- PPPiface = fsm_p->ppp_p->iface;
-
- fsm_log(fsm_p, "Down");
-
- switch ( fsm_p->state ) {
- case fsmREQ_Sent:
- case fsmACK_Rcvd:
- case fsmACK_Sent:
- stop_timer(&(fsm_p->timer));
- fsm_reset(fsm_p);
- break;
-
- case fsmOPENED:
- (*fsm_p->pdc->closing)(fsm_p);
- /* fallthru */
- case fsmTERM_Sent:
- fsm_reset(fsm_p);
- break;
-
- case fsmCLOSED:
- case fsmLISTEN:
- /* nothing to do */
- break;
- };
- }
-
-
- /************************************************************************/
- /* Close the connection */
- void
- fsm_close(fsm_p)
- struct fsm_s *fsm_p;
- {
- if ( fsm_p->pdv == NULL )
- return;
-
- PPPtrace = fsm_p->ppp_p->trace;
- PPPiface = fsm_p->ppp_p->iface;
-
- fsm_log(fsm_p, "Close");
-
- switch ( fsm_p->state ) {
- case fsmOPENED:
- (*fsm_p->pdc->closing)(fsm_p);
- /* fallthru */
- case fsmACK_Sent:
- fsm_p->retry = fsm_p->try_terminate;
- fsm_sendtermreq(fsm_p);
- fsm_p->state = fsmTERM_Sent;
- break;
-
- case fsmREQ_Sent:
- case fsmACK_Rcvd:
- /* simply wait for REQ timeout to expire */
- fsm_p->retry = 0;
- fsm_p->state = fsmTERM_Sent;
- break;
-
- case fsmLISTEN:
- fsm_p->state = fsmCLOSED;
- break;
-
- case fsmTERM_Sent:
- case fsmCLOSED:
- /* nothing to do */
- break;
- };
- }
-
-
- /************************************************************************/
- /* Initialize the fsm for this protocol
- * Called from protocol _init
- */
- void
- fsm_init(fsm_p)
- struct fsm_s *fsm_p;
- {
- struct timer *t = &(fsm_p->timer);
-
- PPP_DEBUG_ROUTINES("fsm_init()");
-
- fsm_p->try_req = fsm_p->pdc->try_req;
- fsm_p->try_nak = fsm_p->pdc->try_nak;
- fsm_p->try_terminate = fsm_p->pdc->try_terminate;
- fsm_reset(fsm_p);
-
- /* Initialize timer */
- t->func = (void (*)())fsm_timeout;
- t->arg = (void *)fsm_p;
- set_timer(t, fsm_p->pdc->timeout);
- fsm_timer(fsm_p);
- stop_timer(t);
- }
-
-
- void
- fsm_free(fsm_p)
- struct fsm_s *fsm_p;
- {
- if ( fsm_p->pdv != NULL ) {
- (*fsm_p->pdc->free)(fsm_p);
-
- free( fsm_p->pdv );
- fsm_p->pdv = NULL;
- }
- }
-
-
-